using System;
using System.Collections.Generic;
using System.Linq;
using Urs.Core;
using Urs.Core.Caching;
using Urs.Core.Data;
using Urs.Data.Domain.Stores;

namespace Urs.Services.Stores
{
    public partial class BrandService : IBrandService
    {
        #region Constants
        private const string MANUFACTURERS_BY_ID_KEY = "Urs.brand.id-{0}";
        private const string MANUFACTURERS_BY_SHOWONPUBLICPAGE = "Urs.brand.showonpublicpage";
        private const string PRODUCTMANUFACTURERS_ALLBYMANUFACTURERID_KEY = "Urs.goodsbrand.allbybrandid-{0}-{1}-{2}-{3}";
        private const string PRODUCTMANUFACTURERS_ALLBYPRODUCTID_KEY = "Urs.goodsbrand.allbygoodsid-{0}-{1}-{2}";
        private const string PRODUCTMANUFACTURERS_BY_ID_KEY = "Urs.goodsbrand.id-{0}";
        private const string MANUFACTURERS_PATTERN_KEY = "Urs.brand.";
        private const string PRODUCTMANUFACTURERS_PATTERN_KEY = "Urs.goodsbrand.";
        #endregion

        #region Fields

        private readonly IRepository<Brand> _brandRepository;
        private readonly IRepository<GoodsBrandMapping> _goodsBrandRepository;
        private readonly IRepository<Goods> _goodsRepository;
        private readonly IWorkContext _workContext;
        private readonly ICacheManager _cacheManager;
        #endregion

        #region Ctor

        public BrandService(ICacheManager cacheManager,
            IRepository<Brand> brandRepository,
            IRepository<GoodsBrandMapping> goodsBrandRepository,
            IRepository<Goods> goodsRepository,
            IWorkContext workContext)
        {
            this._cacheManager = cacheManager;
            this._brandRepository = brandRepository;
            this._goodsBrandRepository = goodsBrandRepository;
            this._goodsRepository = goodsRepository;
            this._workContext = workContext;
        }
        #endregion

        #region Methods

        public virtual void Delete(Brand brand)
        {
            if (brand == null)
                throw new ArgumentNullException("brand");

            brand.Deleted = true;
            Update(brand);
        }

        public virtual IList<Brand> GetAll(bool showHidden = false)
        {
            return GetAll(null, showHidden);
        }

        public virtual IList<Brand> ShowOnPublicPage(bool showHidden = false)
        {
            return _cacheManager.Get<IList<Brand>>(MANUFACTURERS_BY_SHOWONPUBLICPAGE, () =>
            {
                var query = _brandRepository.Table;
                if (!showHidden)
                    query = query.Where(m => m.Published);

                query = query.Where(m => m.ShowOnPublicPage == true);
                query = query.Where(m => !m.Deleted);
                query = query.OrderBy(m => m.DisplayOrder);

                return query.ToList();
            });
        }

        public virtual IList<Brand> GetAll(string brandName, bool showHidden = false)
        {
            var query = _brandRepository.Table;
            if (!showHidden)
                query = query.Where(m => m.Published);
            if (!String.IsNullOrWhiteSpace(brandName))
                query = query.Where(m => m.Name.Contains(brandName));
            query = query.Where(m => !m.Deleted);
            query = query.OrderBy(m => m.DisplayOrder);

            var brands = query.ToList();
            return brands;
        }

        public virtual IPagedList<Brand> GetAll(string brandName,
            int pageIndex, int pageSize, bool showHidden = false)
        {
            var brands = GetAll(brandName, showHidden);
            return new PagedList<Brand>(brands, pageIndex, pageSize);
        }

        public virtual Brand GetById(int brandId)
        {
            if (brandId == 0)
                return null;

            string key = string.Format(MANUFACTURERS_BY_ID_KEY, brandId);
            return _cacheManager.Get(key, () =>
            {
                var brand = _brandRepository.GetById(brandId);
                return brand;
            });
        }

        public virtual void Insert(Brand brand)
        {
            if (brand == null)
                throw new ArgumentNullException("brand");

            _brandRepository.Insert(brand);

            _cacheManager.RemoveByPattern(MANUFACTURERS_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTMANUFACTURERS_PATTERN_KEY);
        }

        public virtual void Update(Brand brand)
        {
            if (brand == null)
                throw new ArgumentNullException("brand");

            _brandRepository.Update(brand);

            _cacheManager.RemoveByPattern(MANUFACTURERS_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTMANUFACTURERS_PATTERN_KEY);
        }

        public virtual void DeleteGoodsBrand(GoodsBrandMapping goodsBrand)
        {
            if (goodsBrand == null)
                throw new ArgumentNullException("goodsBrand");

            _goodsBrandRepository.Delete(goodsBrand);

            _cacheManager.RemoveByPattern(MANUFACTURERS_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTMANUFACTURERS_PATTERN_KEY);
        }

        public virtual IPagedList<GoodsBrandMapping> GetGoodsBrandsByBrandId(int brandId,
            int pageIndex, int pageSize, bool showHidden = false)
        {
            if (brandId == 0)
                return new PagedList<GoodsBrandMapping>(new List<GoodsBrandMapping>(), pageIndex, pageSize);

            string key = string.Format(PRODUCTMANUFACTURERS_ALLBYMANUFACTURERID_KEY, showHidden, brandId, pageIndex, pageSize);
            return _cacheManager.Get(key, () =>
            {
                var query = from pm in _goodsBrandRepository.Table
                            join p in _goodsRepository.Table on pm.GoodsId equals p.Id
                            where pm.BrandId == brandId &&
                                  !p.Deleted &&
                                  (showHidden || p.Published)
                            orderby pm.DisplayOrder
                            select pm;

                var goodsBrands = new PagedList<GoodsBrandMapping>(query, pageIndex, pageSize);
                return goodsBrands;
            });
        }
        
        public virtual int GetTotalNumberOfFeaturedGoodss(int brandId)
        {
            if (brandId == 0)
                return 0;

            var query = from pm in _goodsBrandRepository.Table
                        where pm.BrandId == brandId 
                        select pm;
            var result = query.Count();
            return result;
        }

        public virtual IList<Goods> GetFeaturedGoodss(int brandId, int count)
        {
            if (brandId == 0)
                return new List<Goods>();

            var query = from pm in _goodsBrandRepository.Table
                        where pm.BrandId == brandId
                        orderby pm.DisplayOrder descending
                        select pm.Goods;
            return query.Take(count).ToList();
        }

        public virtual GoodsBrandMapping GetGoodsBrandById(int goodsBrandId)
        {
            if (goodsBrandId == 0)
                return null;

            string key = string.Format(PRODUCTMANUFACTURERS_BY_ID_KEY, goodsBrandId);
            return _cacheManager.Get(key, () =>
            {
                return _goodsBrandRepository.GetById(goodsBrandId);
            });
        }

        public virtual void InsertGoodsBrand(GoodsBrandMapping goodsBrand)
        {
            if (goodsBrand == null)
                throw new ArgumentNullException("goodsBrand");

            _goodsBrandRepository.Insert(goodsBrand);

            _cacheManager.RemoveByPattern(MANUFACTURERS_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTMANUFACTURERS_PATTERN_KEY);
        }

        public virtual void UpdateGoodsBrand(GoodsBrandMapping goodsBrand)
        {
            if (goodsBrand == null)
                throw new ArgumentNullException("goodsBrand");

            _goodsBrandRepository.Update(goodsBrand);

            _cacheManager.RemoveByPattern(MANUFACTURERS_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTMANUFACTURERS_PATTERN_KEY);
        }

        #endregion
    }
}
